﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace _17_Memento
{
    class Program
    {
        /// <summary>
        /// 备忘录模式
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            //备忘录是一种行为设计模式， 允许生成对象状态的快照并在以后将其还原。
            Originator originator = new Originator("Super-duper-super-puper-super.");
            Caretaker caretaker = new Caretaker(originator);
            caretaker.Backup();
            originator.DoSomething();
            caretaker.Backup();
            originator.DoSomething();
            caretaker.Backup();
            originator.DoSomething();
            caretaker.Backup();
            originator.DoSomething();
            caretaker.Backup();
            originator.DoSomething();
            Console.WriteLine("\nClient: Now, let's rollback!\n");
            caretaker.Undo();

            Console.WriteLine("\n\nClient: Once more!\n");
            caretaker.Undo();

            Console.WriteLine();
            Console.ReadKey();

        }
    }
    class Originator
    {
        private string _state;
        public Originator(string state)
        {
            _state = state;
            Console.WriteLine("Originator:My initial state is:"+state);
        }
        public void DoSomething()
        {
            Console.WriteLine("Originator: I'm doing something important");
            _state = GenerateRandomString(30);
            Console.WriteLine($"Originator: and my state has changed to: {_state}");
        }
        private string GenerateRandomString(int length = 30)
        {
            string allowedSymbols = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
            string result = string.Empty;
            while (length > 0)
            {
                result += allowedSymbols[new Random().Next(0, allowedSymbols.Length)];
                Thread.Sleep(12);
                length--;
            }
            return result;
        }
        public IMemento Save()
        {
            return new ConcreteMemento(this._state);
        }
        public void Restore(IMemento memento)
        {
            if(!(memento is ConcreteMemento))
            {
                throw new Exception("Unknown memento class " + memento.ToString());
            }
            _state = memento.GetState();
            Console.Write($"Originator: My state has changed to: {_state}");
        }
    }
    public interface IMemento
    {
        string GetName();
        string GetState();
        DateTime GetDate();
    }
    class ConcreteMemento : IMemento
    {
        private string _state;
        private DateTime _date;
        public ConcreteMemento(string state)
        {
            _state = state;
            _date = DateTime.Now;
        }
        public string GetState()
        {
            return _state;
        }
        public string GetName()
        {
            return $"{_date} / ({_state.Substring(0, 9)})...";
        }
        public DateTime GetDate()
        {
            return _date;
        }
    }
    class Caretaker
    {
        private List<IMemento> _mementos = new List<IMemento>();
        private Originator _originator = null;
        public Caretaker(Originator originator)
        {
            _originator = originator;
        }
        public void Backup()
        {
            Console.WriteLine("\nCaretaker: Saving Originator's state...");
            _mementos.Add(_originator.Save());
        }
        public void Undo()
        {
            if(_mementos.Count == 0)
            {
                return;
            }
            var memento = _mementos.Last();
            _mementos.Remove(memento);
            Console.WriteLine("Caretaker: Restoring state to: " + memento.GetName());
            try
            {
                _originator.Restore(memento);
            }
            catch (Exception)
            {
                Undo();
            }
        }
        public void ShowHistory()
        {
            Console.WriteLine("Caretaker: Here's the list of mementos:");
            foreach (var memento in _mementos)
            {
                Console.WriteLine(memento.GetName());
            }
        }
    }
}
